package advanced.regex;

import java.text.DecimalFormat;
import java.util.Random;

public class NumberCommafy {
	
	private final static int SIZE=999999;//Number of numbers to be generated.
	private final static int MIN=10000000;//minimum number of each generated number. 
	

	/**
	 * Adding comma in between every 3 digits to a large number by parsing the number string.
	 * @param inputNum
	 * @return String
	 */
	private static String stringParserCommafy(String inputNum) {
	    
		String commafiedNum="";
	    Character firstChar= inputNum.charAt(0);
	    
	    /*If there is a positive or negative number sign,
	     *then put the number sign to the commafiedNum and remove the sign from inputNum.
	     */
	    if(firstChar=='+' || firstChar=='-')
	    {
	    	commafiedNum = commafiedNum + Character.toString(firstChar);
	    	inputNum=inputNum.replaceAll("[-\\+]", "");
	    }
	    
	    /*If the input number has decimal places,
	     *then split it into two, save the first part to inputNum
	     *and save the second part to decimalNum which will be appended to the final result at the end.
	     */
	    String [] splittedNum = inputNum.split("\\.");
	    String decimalNum="";
		if(splittedNum.length==2)
		{
			inputNum=splittedNum[0];
			decimalNum="."+splittedNum[1];
		}
	    
		//The main logic for adding commas to the number.
	    int numLength = inputNum.length();
	    for (int i=0; i<numLength; i++) { 
	    	if ((numLength-i)%3 == 0 && i != 0) {
	    		commafiedNum += ",";
	    	}
	    	commafiedNum += inputNum.charAt(i);
	    }

	    return commafiedNum+decimalNum;
	}
	
	/**
	 * Adding comma in between every 3 digits to a large number by using regex.
	 * @param inputNum
	 * @return String
	 */
	private static String regexCommafy(String inputNum)
	{
		String regex = "(\\d)(?=(\\d{3})+$)";
		String [] splittedNum = inputNum.split("\\.");
		if(splittedNum.length==2)
		{
			return splittedNum[0].replaceAll(regex, "$1,")+"."+splittedNum[1];
		}
		else
		{
			return inputNum.replaceAll(regex, "$1,");
		}
	}
	
	/**
	 * Adding comma in between every 3 digits to a large number by using DecimalFormat.
	 * @param inputNum
	 * @return String
	 */
	private static String decimalFormatCommafy(String inputNum)
    {
	    /*If the input number has decimal places,
	     *then split it into two, save the first part to inputNum
	     *and save the second part to decimalNum which will be appended to the final result at the end.
	     */
	    String [] splittedNum = inputNum.split("\\.");
	    String decimalNum="";
		if(splittedNum.length==2)
		{
			inputNum=splittedNum[0];
			decimalNum="."+splittedNum[1];
		}
		
		Double inputDouble=Double.parseDouble(inputNum);
		DecimalFormat myFormatter = new DecimalFormat("###,###");
		String output = myFormatter.format(inputDouble);
		
		
		return output+decimalNum;
    }
	
	private static String [] generateRandomNums()
	{
		String [] numbers = new String[SIZE];
		Random rand = new Random();
		for(int i=0; i<numbers.length;i++)
		{
			numbers[i]=String.valueOf(rand.nextInt(MIN) + MIN);
		}
		
		return numbers;
	}
	
	public static void main(String args[])
	{		 
	        String [] numbers =
	        	{ 
	        		"+123456",
			        "1234567",
			        "-100000000",
			        "+2345676558947589.2546815"};

	        System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<Just a test>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
	        for(int i =0; i<numbers.length; i++)
	        {
	        	System.out.println(stringParserCommafy(numbers[i]));
	        	System.out.println(regexCommafy(numbers[i]));
	        	System.out.println(decimalFormatCommafy(numbers[i]));
	        }
	
	        
	        String [] nums = generateRandomNums();
	        System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"+SIZE+" numbers has be generated, start commafy the numbers>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
	        
	        long startTime = System.nanoTime();
	        for(int i =0; i<nums.length; i++)
	        {
	        	stringParserCommafy(nums[i]);
	        }
	        long endTime   = System.nanoTime();
	        long stringParserCommafyTotalTime = (endTime - startTime)/1000000;
	        System.out.println("stringParserCommafy took " + stringParserCommafyTotalTime + " milliseconds.");
	        
	        
	        startTime = System.currentTimeMillis();
	        for(int i =0; i<nums.length; i++)
	        {
	        	regexCommafy(nums[i]);
	        }
	        endTime   = System.currentTimeMillis();
	        long regexCommafyTotalTime = endTime - startTime;
	        System.out.println("regexCommafy took "+regexCommafyTotalTime+" milliseconds.");
	        
	        
	        startTime = System.currentTimeMillis();
	        for(int i =0; i<nums.length; i++)
	        {
	        	decimalFormatCommafy(nums[i]);
	        }
	        endTime   = System.currentTimeMillis();
	        long decimalFormatCommafyTotalTime = endTime - startTime;
	        System.out.println("decimalFormatCommafy took "+decimalFormatCommafyTotalTime+" milliseconds.");
	        
	        long winner=Math.min(Math.min(stringParserCommafyTotalTime, regexCommafyTotalTime), decimalFormatCommafyTotalTime);
	        
	        if(winner==stringParserCommafyTotalTime)
	        {
	        	System.out.println("!!!!!!!!stringParserCommafy runs the fastest!!!!!!!!");
	        }
	        else if(winner==regexCommafyTotalTime)
	        {
	        	System.out.println("!!!!!!!!regexCommafy runs the fastest!!!!!!!!");
	        }
	        else
	        {
	        	System.out.println("!!!!!!!!decimalFormatCommafy runs the fastest!!!!!!!!");
	        }
	}

}
